home *** CD-ROM | disk | FTP | other *** search
/ Winzipper / Winzipper_ISO.iso / programming / oracle7 7.2 / OCI72 / CDEMO2.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-15  |  13.4 KB  |  509 lines

  1. #ifdef RCSID
  2. static char *RCSid = 
  3.    "$Header: cdemo2.c 7020100.1 94/09/23 22:19:31 cli Generic<base> $ ";
  4. #endif /* RCSID */
  5.  
  6. /* Copyright (c) 1991 by Oracle Corporation */
  7. /*
  8.    NAME
  9.      cdemo2.c - C demo Program # 2
  10.    MODIFIED   (MM/DD/YY)
  11.     emendez    06/28/94 -  fix ansi warnings
  12.     emendez    04/07/94 -  merge from branch 1.8.710.3
  13.     emendez    04/07/94 -  merge changes from branch 1.8.710.2
  14.     gdoherty   04/06/94 -  merge changes from branch 1.8.710.1
  15.     emendez    02/07/94 -  fix for bug 196094
  16.     emendez    02/02/94 -  Fix for bug 157576
  17.     gdoherty   01/31/94 -  make oci header inclusion for ansi or k+r adaptive
  18.     tssmith    03/29/93 -  Removing ANSI material 
  19.     lfeng      03/08/93 -  merge changes from branch 1.6.312.1 
  20.     lfeng      02/10/93 -  portability mods 
  21.     rkooi2     11/27/92 -  Changing e... datatypes to s... 
  22.     lfeng      11/20/92 -  add portability mods
  23.     rkooi2     10/22/92 -  Changes for portability 
  24.     rkooi2     10/18/92 -  Changes to make it portable 
  25.     sjain      08/18/92 -  Changge connect to conect_user
  26.     sjain      03/16/92 -  Creation 
  27. */
  28.  
  29. /* This program accepts arbitrary SQL statements from the user,
  30.    and processes the statement.  Statements may be entered on
  31.    multiple lines, and must be terminated by a semi-colon.
  32.    If a query, the results are printed. */
  33.  
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <ctype.h>
  37. #include <string.h>
  38.  
  39.  
  40. /* Include OCI-specific headers. */
  41. #include <oratypes.h>
  42. #include <ocidfn.h>
  43. #ifdef __STDC__
  44. #include <ociapr.h>
  45. #else
  46. #include <ocikpr.h>
  47. #endif
  48. #include <ocidem.h>
  49.  
  50.  
  51. /* Constants used in this program. */
  52. #define MAX_BINDS               12
  53. #define MAX_ITEM_BUFFER_SIZE    33
  54. #define MAX_SELECT_LIST_SIZE    12
  55. #define MAX_SQL_IDENTIFIER      31
  56.  
  57. #define PARSE_NO_DEFER           0
  58. #define PARSE_V7_LNG             2
  59.  
  60.  
  61. /* Define one logon data area and one cursor data area
  62.    Also define a host data area for orlon.
  63.    (See ocidfn.h for declarations). */
  64. Lda_Def lda;
  65. Cda_Def cda;
  66. ub1     hda[HDA_SIZE];
  67.  
  68. /* Declare an array of bind values. */
  69. text bind_values[MAX_BINDS][MAX_ITEM_BUFFER_SIZE];
  70.  
  71. /* Declare structures for query information. */
  72. struct describe
  73. {
  74.     sb4             dbsize;
  75.     sb2             dbtype;
  76.     sb1             buf[MAX_ITEM_BUFFER_SIZE];
  77.     sb4             buflen;
  78.     sb4             dsize;
  79.     sb2             precision;
  80.     sb2             scale;
  81.     sb2             nullok;
  82. };
  83.  
  84. struct define 
  85. {
  86.     ub1             buf[MAX_ITEM_BUFFER_SIZE];
  87.     float           flt_buf;
  88.     sword           int_buf;
  89.     sb2             indp;
  90.     ub2             col_retlen, col_retcode;
  91. };
  92.  
  93.  
  94. /* Define arrays of describe and define structs. */
  95. struct describe desc[MAX_SELECT_LIST_SIZE];
  96. struct define   def[MAX_SELECT_LIST_SIZE];
  97.  
  98. /*  Declare this programs functions. */
  99. sword  connect_user();
  100. sword  describe_define();
  101. sword  do_binds();
  102. void   do_exit();
  103. void   oci_error();
  104. sword  get_sql_statement();
  105. void   print_header();
  106. void   print_rows();
  107.  
  108. /* Globals */
  109. static text sql_statement[2048];
  110. static sword sql_function;
  111. static sword numwidth = 8;
  112.  
  113.  
  114. void main()
  115. {
  116.     sword ncols;
  117.  
  118.     /* Connect to ORACLE. */
  119.     if (connect_user())
  120.         exit(-1);
  121.  
  122.     /* Open a cursor, exit on error (unrecoverable). */
  123.     if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1))
  124.     {
  125.         printf("Error opening cursor.  Exiting...\n");
  126.         ologof(&lda);
  127.         exit(-1);
  128.     }
  129.  
  130.     /* Process user's SQL statements. */
  131.  
  132.     for (;;)
  133.     {
  134.         /* Get the statement, exit on "exit". */
  135.         if (get_sql_statement())
  136.             do_exit(0);
  137.  
  138.         /* Parse the statement; do not defer the parse,
  139.            so that errors come back right away. */
  140.         if (oparse(&cda, (text *) sql_statement, (sb4) -1,
  141.                  (sword) PARSE_NO_DEFER, (ub4) PARSE_V7_LNG))
  142.         {
  143.             oci_error(&cda);
  144.             continue;
  145.         }
  146.  
  147.         /* Save the SQL function code right after parse. */
  148.         sql_function = cda.ft;
  149.  
  150.         /* Bind any input variables. */
  151.         if ((ncols = do_binds(&cda, sql_statement)) == -1)
  152.             continue;
  153.  
  154.         /* If the statement is a query, describe and define
  155.            all select-list items before doing the oexec. */
  156.         if (sql_function == FT_SELECT)
  157.             if ((ncols = describe_define(&cda)) == -1)
  158.                 continue;
  159.  
  160.         /* Execute the statement. */
  161.         if (oexec(&cda))
  162.         {
  163.             oci_error(&cda);
  164.             continue;
  165.         }
  166.  
  167.         /* Fetch and display the rows for the query. */
  168.         if (sql_function == FT_SELECT)
  169.         {
  170.             print_header(ncols);
  171.             print_rows(&cda, ncols);
  172.         }
  173.  
  174.         /* Print the rows-processed count. */
  175.         if (sql_function == FT_SELECT ||
  176.             sql_function == FT_UPDATE ||
  177.             sql_function == FT_DELETE ||
  178.             sql_function == FT_INSERT)
  179.             printf("\n%d row%c processed.\n", cda.rpc, 
  180.                    cda.rpc == 1 ? '\0' : 's');
  181.         else
  182.             printf("\nStatement processed.\n");
  183.  
  184.     } /* end for (;;) */
  185.  
  186.  
  187. }     /* end main() */
  188.  
  189.  
  190. sword
  191. connect_user()
  192. {
  193.     text username[132];
  194.     text password[132];
  195.     sword n;
  196.  
  197.     /* Three tries to connect. */
  198.     for (n = 3; --n >= 0; )
  199.     {
  200.         printf("Username: ");
  201.         gets((char *) username);
  202.         printf("Password: ");
  203.         gets((char *) password);
  204.  
  205.         if (orlon(&lda, hda, username, -1, password, -1, -1))
  206.         {
  207.             printf("Cannot connect as %s.\n", username);
  208.             printf("Try again.\n\n");
  209.         }
  210.         else
  211.         {
  212.             return 0;
  213.         }
  214.     }
  215.     printf("Connection failed.  Exiting...\n");
  216.     return -1;
  217. }
  218.  
  219.  
  220. /*  Describe select-list items. */
  221.  
  222. sword
  223. describe_define(cda)
  224. Cda_Def *cda;
  225. {
  226.     sword col, deflen, deftyp;
  227.     static ub1 *defptr;
  228.  
  229.     /* Describe the select-list items. */
  230.     for (col = 0; col < MAX_SELECT_LIST_SIZE; col++)
  231.     {
  232.         desc[col].buflen = MAX_ITEM_BUFFER_SIZE;
  233.         if (odescr(cda, col + 1, &desc[col].dbsize,
  234.                    &desc[col].dbtype, &desc[col].buf[0],
  235.                    &desc[col].buflen, &desc[col].dsize,
  236.                    &desc[col].precision, &desc[col].scale,
  237.                    &desc[col].nullok))
  238.         {
  239.             /* Break on end of select list. */
  240.             if (cda->rc == VAR_NOT_IN_LIST)
  241.                 break;
  242.             else
  243.             {
  244.                 oci_error(cda);
  245.                 return -1;
  246.             }
  247.         }
  248.         /* adjust sizes and types for display */
  249.         switch (desc[col].dbtype)
  250.         {
  251.         case NUMBER_TYPE:
  252.             desc[col].dbsize = numwidth;
  253.             /* Handle NUMBER with scale as float. */
  254.             if (desc[col].scale != 0)
  255.             {
  256.                 defptr = (ub1 *) &def[col].flt_buf;
  257.                 deflen = (sword) sizeof(float);
  258.                 deftyp = FLOAT_TYPE;
  259.                 desc[col].dbtype = FLOAT_TYPE;
  260.             }
  261.             else
  262.             {
  263.                 defptr = (ub1 *) &def[col].int_buf;
  264.                 deflen = (sword) sizeof(sword);
  265.                 deftyp = INT_TYPE;
  266.                 desc[col].dbtype = INT_TYPE;
  267.             }
  268.             break;
  269.         default:
  270.             if (desc[col].dbtype == DATE_TYPE)
  271.                 desc[col].dbsize = 9;
  272.             if (desc[col].dbtype == ROWID_TYPE)
  273.                 desc[col].dbsize = 18;
  274.             defptr = def[col].buf;
  275.             deflen = desc[col].dbsize > MAX_ITEM_BUFFER_SIZE ?
  276.               MAX_ITEM_BUFFER_SIZE : desc[col].dbsize + 1;
  277.             deftyp = STRING_TYPE;
  278.             break;
  279.         }
  280.         if (odefin(cda, col + 1,
  281.                    defptr, deflen, deftyp,
  282.                    -1, &def[col].indp, (text *) 0, -1, -1,
  283.                    &def[col].col_retlen,
  284.                    &def[col].col_retcode))
  285.         {
  286.             oci_error(cda);
  287.             return -1;
  288.         }
  289.     }
  290.     return col;
  291. }
  292.  
  293.  
  294. /*  Bind input variables. */
  295.  
  296. sword
  297. do_binds(cda, stmt_buf)
  298. Cda_Def *cda;
  299. text *stmt_buf;
  300. {
  301.     sword i, in_literal, n;
  302.     text *cp, *ph;
  303.  
  304.     /* Find and bind input variables for placeholders. */
  305.     for (i = 0, in_literal = FALSE, cp = stmt_buf;
  306.               *cp && i < MAX_BINDS; cp++)
  307.     {
  308.         if (*cp == '\'')
  309.             in_literal = ~in_literal;
  310.         if (*cp == ':' && !in_literal)
  311.         {
  312.             for (ph = ++cp, n = 0;
  313.                  *cp && (isalnum(*cp) || *cp == '_')
  314.                      && n < MAX_SQL_IDENTIFIER;
  315.                  cp++, n++
  316.                 )
  317.                 ;
  318.             *cp = '\0';
  319.             printf("Enter value for %s: ", ph);
  320.             gets((char *) &bind_values[i][0]);
  321.  
  322.             /* Do the bind, using obndrv().
  323.                NOTE:  the bind variable address must be static.
  324.                This would not work if bind_values were an
  325.                auto on the do_binds stack. */
  326.             if (obndrv(cda, ph, -1, &bind_values[i][0], -1, VARCHAR2_TYPE,
  327.                        -1, (sb2 *) 0, (text *) 0, -1, -1))
  328.             {
  329.                 oci_error(cda);
  330.                 return -1;
  331.             }
  332.             i++;
  333.         }   /* end if (*cp == ...) */
  334.     }       /* end for () */
  335.     return i;
  336. }
  337.  
  338.  
  339.  
  340. /*  Clean up and exit.  LDA and CDA are
  341.     global. */
  342. void
  343. do_exit(rv)
  344. sword rv;
  345. {
  346.     if (oclose(&cda))
  347.         fputs("Error closing cursor!\n", stdout);
  348.     if (ologof(&lda))
  349.         fputs("Error logging off!\n", stdout);
  350.     exit(rv);
  351. }
  352.  
  353.  
  354. void
  355. oci_error(cda)
  356. Cda_Def *cda;
  357. {
  358.     text msg[512];
  359.     sword n;
  360.  
  361.     fputs("\n-- ORACLE ERROR --\n", stderr);
  362.     n = oerhms(&lda, cda->rc, msg, (sword) sizeof (msg));
  363.     fprintf(stderr, "%.*s", n, msg);
  364.     fprintf(stderr, "Processing OCI function %s\n",
  365.             oci_func_tab[cda->fc]);
  366.     fprintf(stderr, "Do you want to continue? [yn]: ");
  367.     fgets((char *) msg, (int) sizeof (msg), stdin);
  368.     if (*msg != '\n' && *msg != 'y' && *msg != 'Y')
  369.         do_exit(1);
  370.     fputc('\n', stdout);
  371. }
  372.  
  373.  
  374. sword
  375. get_sql_statement()
  376. {
  377.     text cbuf[1024];
  378.     text *cp;
  379.     sword stmt_level;
  380.  
  381.  
  382.     for (stmt_level = 1; ;)
  383.     {
  384.         if (stmt_level == 1)
  385.         {
  386.             /* Init statement buffer and print prompt. */
  387.             *sql_statement = '\0';
  388.             fputs("\nOCISQL> ", stdout);
  389.         }
  390.         else
  391.         {
  392.             printf("%3d     ", stmt_level);
  393.         }
  394.  
  395.         /* Get (part of) a SQL statement. */
  396.         gets((char *) cbuf);
  397.         if (*cbuf == '\0')
  398.             continue;
  399.         if (strncmp((char *) cbuf, "exit", 4) == 0)
  400.             return -1;
  401.  
  402.         /* Concatenate to statement buffer. */
  403.         if (stmt_level > 1)
  404.             strcat((char *) sql_statement, " ");
  405.         strcat((char *) sql_statement, (char *) cbuf);
  406.  
  407.         /* Check for possible terminator. */
  408.         cp = &sql_statement[strlen((char *) sql_statement) - 1];
  409.         
  410.         while (isspace(*cp))
  411.             cp--;
  412.         if (*cp == ';')
  413.         {
  414.             *cp = '\0';
  415.             break;
  416.         }
  417.         stmt_level++;
  418.     }
  419.     return 0;
  420. }
  421.  
  422.  
  423. void
  424. print_header(ncols)
  425. sword ncols;
  426. {
  427.     sword col, n;
  428.  
  429.     fputc('\n', stdout);
  430.  
  431.     for (col = 0; col < ncols; col++)
  432.     {
  433.         n = desc[col].dbsize - desc[col].buflen;
  434.         if (desc[col].dbtype == FLOAT_TYPE ||
  435.             desc[col].dbtype == INT_TYPE)
  436.         {
  437.             printf("%*c", n, ' ');
  438.             printf("%*.*s", desc[col].buflen,
  439.                    desc[col].buflen, desc[col].buf);
  440.         }
  441.         else
  442.         {
  443.             printf("%*.*s", desc[col].buflen,
  444.                    desc[col].buflen, desc[col].buf);
  445.             printf("%*c", n, ' ');
  446.         }
  447.         fputc(' ', stdout);
  448.     }            
  449.     fputc('\n', stdout);
  450.  
  451.     for (col = 0; col < ncols; col++)
  452.     {
  453.         for (n = desc[col].dbsize; --n >= 0; )
  454.             fputc('-', stdout);
  455.         fputc(' ', stdout);
  456.     }
  457.     fputc('\n', stdout);
  458. }
  459.  
  460.  
  461. void
  462. print_rows(cda, ncols)
  463. Cda_Def *cda;
  464. sword ncols;
  465. {
  466.     sword col, n;
  467.  
  468.     for (;;)
  469.     {
  470.         fputc('\n', stdout);
  471.         /* Fetch a row.  Break on end of fetch,
  472.            disregard null fetch "error". */
  473.         if (ofetch(cda))
  474.         {
  475.             if (cda->rc == NO_DATA_FOUND)
  476.                 break;
  477.             if (cda->rc != NULL_VALUE_RETURNED)
  478.                 oci_error(cda);
  479.         }
  480.         for (col = 0; col < ncols ; col++)
  481.         {
  482.             /* Check col. return code for null.  If
  483.                null, print n spaces, else print value. */
  484.             if (def[col].indp < 0)
  485.                 printf("%*c", desc[col].dbsize, ' ');
  486.             else
  487.             {
  488.                 switch (desc[col].dbtype)
  489.                 {
  490.                 case FLOAT_TYPE:
  491.                     printf("%*.*f", numwidth, 2, def[col].flt_buf);
  492.                     break;
  493.                 case INT_TYPE:
  494.                     printf("%*d", numwidth, def[col].int_buf);
  495.                     break;
  496.                 default:
  497.                     printf("%s", def[col].buf);
  498.                     n = desc[col].dbsize - strlen((char *) def[col].buf);
  499.                     if (n > 0)
  500.                         printf("%*c", n, ' ');
  501.                     break;
  502.                 }
  503.             }
  504.             fputc(' ', stdout);
  505.         }
  506.     }  /* end for (;;) */
  507. }
  508.  
  509.